home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 432_01 / ptmid3 / samples.c < prev    next >
C/C++ Source or Header  |  1994-07-01  |  7KB  |  280 lines

  1. /*
  2.  * samples.c: Routines for Ptmid to deal with samples. The use of these
  3.  * routines makes it easy to add support for further sample formats.
  4.  *
  5.  * author: Andrew Scott  (c)opyright 1994
  6.  *
  7.  * date: 30/6/1994
  8.  */
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include "ptmid.h"
  12. #include "samples.h"
  13.  
  14. /** Define VC enumerated type to specify sort of VOC-chunk to look for **/
  15. enum VC { VC_term = 0, VC_voc, VC_cnt, VC_spc, VC_mrk, VC_txt,
  16.   VC_rep, VC_enr };
  17.  
  18. /*
  19.  * CatFn: Given two filenames, will return a pointer to a copy of them
  20.  * concatenated together.
  21.  *
  22.  * date: 30/6/1994
  23.  */
  24. Sz CatFn(Sz fnA, Sz fnB)
  25. {
  26.   static Fn fnBuff;
  27.   Sz szT = fnBuff;
  28.  
  29.   while (*szT = *(fnA++))
  30.     szT++;
  31.   while (*(szT++) = *(fnB++));
  32.   return fnBuff;
  33. }
  34.  
  35. /*
  36.  * FIsvoc: Given a file pointer, will return NZ if the file is a VOC
  37.  * file.
  38.  *
  39.  * date: 30/6/1994
  40.  */
  41. int FIsvoc(FILE *pfile)
  42. {
  43.   char rgbClbuff[20];
  44.  
  45.   fseek(pfile, 0, SEEK_SET);
  46.   if (fread(rgbClbuff, 20, 1, pfile) == 0)
  47.     return 0;
  48.   return !strncmp(rgbClbuff, "Creative Voice File\32", 20);
  49. }
  50.  
  51. /*
  52.  * FIswav: Given a file pointer, will return NZ if the file is a WAV
  53.  * file.
  54.  *
  55.  * date: 1/7/1994
  56.  */
  57. int FIswav(FILE *pfile)
  58. {
  59.   char rgbRiffbuff[12];
  60.  
  61.   fseek(pfile, 0, SEEK_SET);
  62.   if (fread(rgbRiffbuff, 12, 1, pfile) == 0)
  63.     return 0;
  64.   return !strncmp(rgbRiffbuff, "RIFF", 4) &&
  65.     !strncmp(rgbRiffbuff + 8, "WAVE", 4);
  66. }
  67.  
  68. /*
  69.  * LongRead: Returns the next long integer from the given file.
  70.  *
  71.  * date: 1/7/1994
  72.  */
  73. unsigned long LongRead(FILE *pfile)
  74. {
  75.   unsigned long dw;
  76.  
  77.   dw = getc(pfile);
  78.   dw += (unsigned long) getc(pfile) << 8;
  79.   dw += (unsigned long) getc(pfile) << 16;
  80.   dw += (unsigned long) getc(pfile) << 24;
  81.   return dw;
  82. }
  83.  
  84. /*
  85.  * TriRead: Returns the next byte triple from the given file.
  86.  *
  87.  * date: 1/7/1994
  88.  */
  89. unsigned long TriRead(FILE *pfile)
  90. {
  91.   unsigned long dw;
  92.  
  93.   dw = getc(pfile);
  94.   dw += (unsigned long) getc(pfile) << 8;
  95.   dw += (unsigned long) getc(pfile) << 16;
  96.   return dw;
  97. }
  98.  
  99. /*
  100.  * WordRead: Returns the next word from the given file.
  101.  *
  102.  * date: 1/7/1994
  103.  */
  104. unsigned WordRead(FILE *pfile)
  105. {
  106.   unsigned w;
  107.  
  108.   w = getc(pfile);
  109.   w += (unsigned) getc(pfile) << 8;
  110.   return w;
  111. }
  112.  
  113. /*
  114.  * Govoc: Given a VOC-file and a chunk-tag, will advance the file to
  115.  * the start of the chunk if it exists and return NZ, else will return Z.
  116.  *
  117.  * date: 1/7/1994
  118.  */
  119. int Govoc(FILE *pfile, enum VC vcChunk)
  120. {
  121.   int bT;
  122.   unsigned long len;
  123.  
  124.   fseek(pfile, 20, SEEK_SET);
  125.   len = WordRead(pfile);
  126.   fseek(pfile, len, SEEK_SET);
  127.   bT = getc(pfile);
  128.   while (EOF != bT && 0 != bT && bT != vcChunk) {
  129.     len = TriRead(pfile);
  130.     if (0 < len)
  131.       fseek(pfile, len, SEEK_CUR);
  132.     bT = getc(pfile);
  133.   }
  134.   return bT == vcChunk;
  135. }
  136.  
  137. /*
  138.  * Gowav: Given a wave-file and a chunk-name, will advance the file to
  139.  * the start of the chunk if it exists and return NZ, else will return Z.
  140.  *
  141.  * date: 1/7/1994
  142.  */
  143. int Gowav(FILE *pfile, Sz szChunk)
  144. {
  145.   char rgbBuff[4];
  146.   unsigned long len;
  147.  
  148.   fseek(pfile, 12, SEEK_SET);
  149.   fread(rgbBuff, 4, 1, pfile);
  150.   while (!feof(pfile) && strncmp(szChunk, rgbBuff, 4)) {
  151.     len = LongRead(pfile);
  152.     if (fseek(pfile, len, SEEK_CUR) || !fread(rgbBuff, 4, 1, pfile))
  153.       return 0;
  154.   }
  155.   return !feof(pfile);
  156. }
  157.  
  158. /*
  159.  * FreqGetFn: Given a sample's filename, will return the frequency of
  160.  * that sample.
  161.  *
  162.  * date: 30/6/1994
  163.  */
  164. unsigned FreqGetFn(Sz fnSample)
  165. {
  166.   unsigned freq = C2FREQUENCY;
  167.   int wData;
  168.   FILE *pfile;
  169.  
  170.   pfile = fopen(CatFn(fnSampath, fnSample), "rb"); /** Open file **/
  171.   if (NULL != pfile) {
  172.     if (FIsvoc(pfile)) { /** If a VOC file **/
  173.       fseek(pfile, 20, SEEK_SET);
  174.       if ((wData = getc(pfile)) != EOF &&
  175.        !fseek(pfile, ((long) getc(pfile) << 8) | wData, SEEK_SET) &&
  176.        getc(pfile) == 1) { /*** Go to start of sound info ***/
  177.         getc(pfile); /*** Skip length ***/
  178.         getc(pfile);
  179.         getc(pfile);
  180.         wData = getc(pfile); /*** Get sample rate ***/
  181.         freq = (unsigned) (1000000L / (256 - wData));
  182.       }
  183.     } else if (FIswav(pfile) && Gowav(pfile, "fmt ")) { /** If a WAV file **/
  184.       fseek(pfile, 8, SEEK_CUR); /*** Go to position of freqency ***/
  185.       freq = (unsigned) LongRead(pfile); /*** Get sample rate ***/
  186.     }
  187.     fclose(pfile);
  188.   }
  189.   return freq;
  190. }
  191.  
  192. /*
  193.  * LenOutPfileFn: Given an output file and a sample filename, writes the
  194.  * sample to the output file and returns the number of bytes written.
  195.  * If fSignout is NZ, data will be written in signed format, else in
  196.  * unsigned.
  197.  *
  198.  * date: 30/6/1994
  199.  *       1/7/1994 - added WAV format
  200.  *       2/7/1994 - added fSignout
  201.  */
  202. long LenOutPfileFn(FILE *pfileOut, Sz fnSample, int fSignout)
  203. {
  204.   FILE *pfileSample;
  205.   long cSample = 0;
  206.  
  207.   pfileSample = fopen(CatFn(fnSampath, fnSample), "rb");
  208.   if (NULL == pfileSample)
  209.     return 0;
  210.   if (FIsvoc(pfileSample)) { /** Is sample file a VOC file? **/
  211.     unsigned long cch;
  212.     int ch;
  213.  
  214.     Govoc(pfileSample, VC_voc);
  215.     cch = TriRead(pfileSample) - 2; /*** Get length ***/
  216.     if (131072 < cch)
  217.       cch = 131072;
  218.     else if (cch & 1) /*** Ensure length is even ***/
  219.       cch &= ~1;
  220.     cSample = cch;
  221.     fseek(pfileSample, 2, SEEK_CUR); /*** Skip rate + compression ***/
  222.     while (cch-- && (ch = getc(pfileSample)) != EOF)
  223.       if (fSignout)
  224.         putc(ch ^ 128, pfileOut); /*** Copy the samples ***/
  225.       else
  226.         putc(ch, pfileOut);
  227.  
  228.   } else if (FIswav(pfileSample)) { /** Is sample type WAV? **/
  229.     unsigned numchan, align, numbits, bytechan;
  230.     int ch;
  231.     unsigned long cch;
  232.  
  233.     Gowav(pfileSample, "fmt ");
  234.     fseek(pfileSample, 6, SEEK_CUR);
  235.     numchan = WordRead(pfileSample); /*** Get #channels ***/
  236.     fseek(pfileSample, 8, SEEK_CUR);
  237.     align = WordRead(pfileSample); /*** Get block alignment (in bytes) ***/
  238.     numbits = WordRead(pfileSample); /*** Get #bits/sample ***/
  239.     bytechan = align / numchan; /*** Calc bytes/channel ***/
  240.     Gowav(pfileSample, "data");
  241.     cch = LongRead(pfileSample) / align;
  242.     if (131072 < cch)
  243.       cch = 131072;
  244.     else if (cch & 1) /*** Ensure length is even ***/
  245.       cch &= ~1;
  246.     cSample = cch;
  247.     while (cch--) { /*** With each sample.. ***/
  248.       if (1 < bytechan)
  249.         fseek(pfileSample, bytechan - 1, SEEK_CUR);
  250.       ch = getc(pfileSample); /*** Get most sig. byte ***/
  251.       if ((numbits > 8) == fSignout)
  252.         putc(ch, pfileOut); /*** Output it ***/
  253.       else
  254.         putc(ch ^ 128, pfileOut);
  255.       if (bytechan != align) /*** Skip any remaining channels of sample ***/
  256.         fseek(pfileSample, align - bytechan, SEEK_CUR);
  257.     }
  258.  
  259.   } else { /** Sample file must be a SMP file **/
  260.     long cch;
  261.     int ch;
  262.  
  263.     fseek(pfileSample, 0, SEEK_END);
  264.     cch = ftell(pfileSample);
  265.     if (131072 < cch)
  266.       cch = 131072;
  267.     else if (cch & 1) /** Ensure length is even **/
  268.       cch &= ~1;
  269.     cSample = cch;
  270.     fseek(pfileSample, 0, SEEK_SET);
  271.     while ((ch = getc(pfileSample)) != EOF)
  272.       if (fSignout)
  273.         putc(ch, pfileOut);
  274.       else
  275.         putc(ch ^ 128, pfileOut);
  276.   }
  277.   fclose(pfileSample);
  278.   return cSample;
  279. }
  280.